package ongd.web;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import ongd.negocio.gestion.ControladorApadrinamiento;
import ongd.negocio.gestion.ControladorIndice;
import ongd.negocio.gestion.ControladorPadrino;
import ongd.negocio.gestion.ControladorProyectoSC;
import ongd.negocio.gestion.ControladorSocio;
import ongd.negocio.gestion.ControladorUsuario;
import ongd.negocio.gestion.ControladorVoluntario;
import ongd.negocio.gestion.Indice;
import ongd.negocio.sesion.ControladorSesion;
import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.component.submenu.Submenu;
import org.primefaces.context.RequestContext;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;

/**
 * Clase que realiza las operaciones necesarias de la sesión.
 *
 * @author <a href="mailto:egi0002@alu.ubu.es">Elena García Iglesias</a>
 * @author <a href="mailto:cms0021@alu.ubu.es">Cristina Martínez Sanz</a>
 * @version 1.0 20120124
 *
 */
@ManagedBean
@SessionScoped
public class SesionBean {

    /**
     * Objeto del tipo ControladorSesion que nos servirá para realizar
     * las operaciones relacionadas con la sesión que esté abierta.
     */
    private ControladorSesion controladorSesion;
    /**
     * Objeto de tipo PhaseListenerImpl.
     */
    private PhaseListenerImpl phaseListenerImpl;
    /**
     * Objeto de tipo String que va a contener ciertos valores necesarios
     * para el correcto funcionamiento de la aplicación.
     */
    private String strVariable;
    /**
     * Objeto de tipo String que va a contener el nombre de usuario que
     * inicia sesión en la zona privada de la aplicación.
     */
    private String nombreUsuario;
    /**
     * Objeto de tipo String que va a corresponder con el id del usuario
     * que va a iniciar sesión en la zona privada.
     */
    private String idUsuario;
    /**
     * Objeto de tipo String que va a corresponder con el password del 
     * usuario que va a iniciar sesión en la aplicación.
     */
    private String passwordUsuario;
    /**
     * Objeto de tipo boolean que nos indica si el usuario ha iniciado sesión.
     */
    private boolean usuarioRegistrado;
    /**
     * Objeto de tipo MenuModel que mostrará el menu en la página web.
     */
    private MenuModel menuWeb;

    /** 
     * Constructor de la clase.
     */
    public SesionBean() {
        controladorSesion = new ControladorSesion(true);
        boolean blnConexionBD = controladorSesion.conectarBD(false);
        cargarMenu();
        usuarioRegistrado = false;
        nombreUsuario = new String();
        MenuItem item = new MenuItem();
        item.setValue("Principal");
    }

    /**
     * Método que carga el menú en la página web.
     */
    public void cargarMenu() {
        List<Indice> listaIndice = getControladorIndice().obtenerIndice();
        menuWeb = new DefaultMenuModel();
        //Cojo el nodo padre
        Indice principal = listaIndice.get(0);
        if (principal.getNombre().compareTo("Principal") == 0) {
            annadirMenu(false, principal, null);
        }
    }

    /**
     * Método recursivo que añade un elemento del menu al menu de la página 
     * web.
     * @param bln Booleano que indica si hay que añadir directamente el 
     * elemento al menu o asociarlo con un submenu
     * @param nodo Indice que crearemos en el menú
     * @param sm Submenu al que pertenece el indice
     */
    private void annadirMenu(boolean bln, Indice nodo, Submenu sm) {
        if (nodo.getNombre().compareTo("Principal") == 0) {
            if (!nodo.getIndiceList().isEmpty()) {
                for (Indice i : nodo.getIndiceList()) {
                    annadirMenu(true, i, null);
                }
            }
        } else {
            if (!nodo.getIndiceList().isEmpty()) {
                Submenu subMenu = new Submenu();
                subMenu.setLabel(nodo.getNombre());
                if (sm != null) {
                    sm.getChildren().add(subMenu);
                } else if (bln) {
                    menuWeb.addSubmenu(subMenu);
                }
                for (Indice i : nodo.getIndiceList()) {
                    annadirMenu(false, i, subMenu);
                }
            } else {
                //si no tiene hijos
                MenuItem menuI = new MenuItem();
                menuI.setValue(nodo.getNombre());
                menuI.setUrl("/paginas/" + nodo.getUrl());
                menuI.setTarget("iframeCentral");
                if (bln) {
                    menuWeb.addMenuItem(menuI);
                } else if (sm != null) {
                    sm.getChildren().add(menuI);
                }
            }
        }
    }

    /**
     * Método que inicia la sesión del usuario.
     * @return null
     */
    public String iniciarSesion() {
        RequestContext requestContext = RequestContext.getCurrentInstance();
        if (nombreUsuario.compareTo("") != 0) {
            if (passwordUsuario.compareTo("") != 0) {
                if (getControladorUsuario().comprobarUsuario(nombreUsuario, passwordUsuario)) {
                    try {
                        usuarioRegistrado = true;
                        FacesContext.getCurrentInstance().getExternalContext().redirect("zonaP.xhtml");
                    } catch (IOException ex) {
                        Logger.getLogger(SesionBean.class.getName()).log(Level.SEVERE, null, ex);
                    }
                } else {
                    requestContext.addCallbackParam("datosIncorrectos", true);
                }
            } else {
                requestContext.addCallbackParam("faltaContraseña", true);
            }
        } else {
            requestContext.addCallbackParam("faltaNombre", true);
        }
        return null;
    }

    /**
     * Método que comprueba si la sesión ha sido iniciada o no, si no ha sido
     * iniciada redireccionará a la página principal de la aplicación.
     * @return true o false
     */
    public boolean iniciadaSesion() {
        if (!isUsuarioRegistrado()) {
            try {
                FacesContext.getCurrentInstance().getExternalContext().redirect("/AplicacionONGD/");
            } catch (IOException ex) {
                Logger.getLogger(SesionBean.class.getName()).log(Level.SEVERE, null, ex);
            }
            return false;
        } else {
            return true;
        }
    }

    /**
     * Método que cierra la sesión.
     */
    public void cerrarSesion() {
        usuarioRegistrado = false;
        nombreUsuario = new String();
        passwordUsuario = new String();
        try {
            FacesContext.getCurrentInstance().getExternalContext().redirect("/AplicacionONGD/");
        } catch (IOException ex) {
            Logger.getLogger(SesionBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Método que envia una alerta cuando el usuario ha olvidado su contraseña.
     * @return null
     */
    public String enviarEmail() {
        RequestContext requestContext = RequestContext.getCurrentInstance();
        if (getControladorUsuario().enviarEmailUsuario(idUsuario)) {
            idUsuario = new String();
            requestContext.addCallbackParam("envioEmail", true);
        } else {
            idUsuario = new String();
            requestContext.addCallbackParam("noExiste", true);
        }
        return null;
    }

    /**
     * Método que guarda un fichero adjunto en una  carpeta de la aplicación.
     * @param ficheroOriginal fichero original
     * @param ficheroCopia fichero donde guadaremos el contenido del original
     */
    public void guardar(String ficheroOriginal, InputStream ficheroCopia) {
        try {
            // Se abre el fichero original para lectura
            BufferedInputStream bufferedInput = new BufferedInputStream(ficheroCopia);

            //Para saber donde está el directorio por defecto donde va a guardar el fichero.
            File f = new File(".");
            System.out.println("Ruta defecto: " + f.getAbsolutePath());
            String url = "webapps\\AplicacionONGD\\ficherosAdjuntos\\";
            // Se abre el fichero donde se hará la copia
            FileOutputStream fileOutput = new FileOutputStream(url + ficheroOriginal);
            BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutput);

            // Bucle para leer de un fichero y escribir en el otro.
            byte[] array = new byte[1000];
            int leidos = bufferedInput.read(array);
            while (leidos > 0) {
                bufferedOutput.write(array, 0, leidos);
                leidos = bufferedInput.read(array);
            }

            // Cierre de los ficheros
            bufferedInput.close();
            bufferedOutput.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Método que devuelve el valor de la variable controladorSesion.
     * @return controladorSesion
     * @see #setControladorSesion
     */
    public ControladorSesion getControladorSesion() {
        return controladorSesion;
    }

    /**
     * Método que establece el valor de la variable controladorSesion.
     * @param controladorSesion Nuevo valor de la variable
     * @see #getControladorSesion
     */
    public void setControladorSesion(ControladorSesion controladorSesion) {
        this.controladorSesion = controladorSesion;
    }

    /**
     * Método que devuelve un objeto de tipo ControladorSocio.
     * @return controladorSocio
     */
    public ControladorSocio getControladorSocio() {
        return controladorSesion.getControladorSocio();
    }

    /**
     * Método que devuelve un objeto de tipo ControladorApadrinamiento.
     * @return controladorApadrinamiento
     */
    public ControladorApadrinamiento getControladorApadrinamiento() {
        return controladorSesion.getControladorApadrinamiento();
    }

    /**
     * Método que devuelve un objeto de tipo ControladorProyectoSC.
     * @return controladorProyectoSC
     */
    public ControladorProyectoSC getControladorProyectoSC() {
        return controladorSesion.getControladorProyectoSC();
    }

    /**
     * Método que devuelve un objeto de tipo ControladorPadrino.
     * @return controladorPadrino
     */
    public ControladorPadrino getControladorPadrino() {
        return controladorSesion.getControladorPadrino();
    }

    /**
     * Método que devuelve un objeto de tipo ControladorVoluntario.
     * @return controladorVoluntario
     */
    public ControladorVoluntario getControladorVoluntario() {
        return controladorSesion.getControladorVoluntario();
    }

    /**
     * Método que devuelve un objeto de tipo ControladorIndice.
     * @return controladorIndice
     */
    public ControladorIndice getControladorIndice() {
        return controladorSesion.getControladorIndice();
    }

    /**
     * Método que devuelve un objeto de tipo ControladorUsuario.
     * @return controladorUsuario
     */
    public ControladorUsuario getControladorUsuario() {
        return controladorSesion.getControladorUsuario();
    }

    /**
     * Método que devuelve un objeto de tipo PhaseListenerImpl.
     * @return phaseListenerImpl
     * @see #setPhaseListenerImpl
     */
    public PhaseListenerImpl getPhaseListenerImpl() {
        return phaseListenerImpl;
    }

    /**
     * Método que establece el valor a la variable phasListenerImpl.
     * @param phaseListenerImpl Nuevo valor de la variable
     * @see #getPhaseListenerImpl
     */
    public void setPhaseListenerImpl(PhaseListenerImpl phaseListenerImpl) {
        this.phaseListenerImpl = phaseListenerImpl;
    }

    /**
     * Método que devuelve el valor de la variable strVariable.
     * @return strVariable
     * @see #setStrVariable
     */
    public String getStrVariable() {
        return strVariable;
    }

    /**
     * Método que establece un valor a la variable strVariable.
     * @param strVariable Nuevo valor de la variable
     * @see #getStrVariable
     */
    public void setStrVariable(String strVariable) {
        this.strVariable = strVariable;
    }

    /**
     * Método que devuelve el valor de la variable nombreUsuario.
     * @return nombreUsuario
     * @see #setNombreUsuario
     */
    public String getNombreUsuario() {
        return nombreUsuario;
    }

    /**
     * Método que establece el valor de la variable nombreUsuario.
     * @param nombreUsuario Nuevo valor de la variable
     * @see #getNombreUsuario
     */
    public void setNombreUsuario(String nombreUsuario) {
        this.nombreUsuario = nombreUsuario;
    }

    /**
     * Método que devuelve el valor de la variable passwordUsuario.
     * @return passwordUsuario
     * @see #setPasswordUsuario
     */
    public String getPasswordUsuario() {
        return passwordUsuario;
    }

    /**
     * Método que establece el valor de la variable passwordUsuario.
     * @param passwordUsuario Nuevo valor de la variable
     * @see #getPasswordUsuario
     */
    public void setPasswordUsuario(String passwordUsuario) {
        this.passwordUsuario = passwordUsuario;
    }

    /**
     * Método que devuelve el valor de la variable usuarioRegistrado.
     * @return usuarioRegistrado
     */
    public boolean isUsuarioRegistrado() {
        return usuarioRegistrado;
    }

    /**
     * Método uqe establece el valor de la variable usuarioRegistrado.
     * @param usuarioRegistrado Nuevo valor de la variable
     */
    public void setUsuarioRegistrado(boolean usuarioRegistrado) {
        this.usuarioRegistrado = usuarioRegistrado;
    }

    /**
     * Método que devuelve el valor de la variable idUsuario.
     * @return idUsuario
     * @see #setIdUsuario
     */
    public String getIdUsuario() {
        return idUsuario;
    }

    /**
     * Método que establece el valor de la variable idUsuario.
     * @param idUsuario Nuevo valor de la variable
     * @see #getIdUsuario
     */
    public void setIdUsuario(String idUsuario) {
        this.idUsuario = idUsuario;
    }

    /**
     * Método que devuelve el valor de la variable menuWeb.
     * @return menuWeb
     * @see #setMenuWeb
     */
    public MenuModel getMenuWeb() {
        return menuWeb;
    }

    /**
     * Método que establece el valor de la variable menuWeb.
     * @param menuWeb Nuevo valor de la variable
     * @see #getMenuWeb
     */
    public void setMenuWeb(MenuModel menuWeb) {
        this.menuWeb = menuWeb;
    }
}
